#include "tmc5130.h"
#include "spi.h"
#include "stdint.h"

/**
  * @brief  TMC5130初始化配置
  * @param  None
  * @retval None
  */
void TMC5130_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    /* 使能时钟 */
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_SPI2_CLK_ENABLE();

    /* 配置SPI2引脚: PB13(SCK), PB14(MISO), PB15(MOSI) */
    GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* 初始化时设置引脚为高电平 */
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET);

    /* 配置SPI2的片选引脚CS：PB12 */
    GPIO_InitStruct.Pin = TMC_CS_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(TMC_CS_GPIO_Port, &GPIO_InitStruct);
    HAL_GPIO_WritePin(TMC_CS_GPIO_Port, TMC_CS_Pin, GPIO_PIN_SET);

    /* 配置TMC5130的使能引脚EN：PA7 */
    GPIO_InitStruct.Pin = TMC_EN_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(TMC_EN_GPIO_Port, &GPIO_InitStruct);
    HAL_GPIO_WritePin(TMC_EN_GPIO_Port, TMC_EN_Pin, GPIO_PIN_RESET); /* 使能引脚EN拉低有效 */

    /* 配置TMC5130的SPI_Mode和SD_Mode引脚：PA5(SPI_Mode), PA6(SD_Mode) */
    GPIO_InitStruct.Pin = TMC_MODE_Pin | TMC_SD_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(TMC_MODE_GPIO_Port, &GPIO_InitStruct);

    /* 设置工作模式1：SPI_Mode=1，SD_Mode=0 */
    HAL_GPIO_WritePin(TMC_MODE_GPIO_Port, TMC_MODE_Pin, GPIO_PIN_SET);   /* SPI_Mode设置为高电平 */
    HAL_GPIO_WritePin(TMC_SD_GPIO_Port, TMC_SD_Pin, GPIO_PIN_RESET);     /* SD_Mode设置为低电平 */

    /* 配置SPI2 */
    hspi2.Instance = SPI2;
    hspi2.Init.Mode = SPI_MODE_MASTER;
    hspi2.Init.Direction = SPI_DIRECTION_2LINES;
    hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi2.Init.CLKPolarity = SPI_POLARITY_HIGH;
    hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;
    hspi2.Init.NSS = SPI_NSS_SOFT;
    hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
    hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi2.Init.CRCPolynomial = 10;
    HAL_SPI_Init(&hspi2);
}

/**
  * @brief  TMC5130 SPI写数据
  * @param  buff: 要写入的数据缓冲区
  * @param  size: 数据长度
  * @retval None
  */
void TMC5130_SPI_Write(uint8_t* buff, uint8_t size)
{
    /* 拉低CS引脚，开始传输 */
    HAL_GPIO_WritePin(TMC_CS_GPIO_Port, TMC_CS_Pin, GPIO_PIN_RESET);
    
    /* 发送数据并接收返回值 */
    HAL_SPI_TransmitReceive(&hspi2, buff, buff, size, HAL_MAX_DELAY);
    
    /* 拉高CS引脚，结束传输 */
    HAL_GPIO_WritePin(TMC_CS_GPIO_Port, TMC_CS_Pin, GPIO_PIN_SET);
}

/**
  * @brief  TMC5130 SPI读数据
  * @param  bufftx: 发送的数据缓冲区
  * @param  buffrx: 接收的数据缓冲区
  * @param  size: 数据长度
  * @retval None
  */
void TMC5130_SPI_Read(uint8_t* bufftx, uint8_t* buffrx, uint8_t size)
{
    /* 拉低CS引脚，开始传输 */
    HAL_GPIO_WritePin(TMC_CS_GPIO_Port, TMC_CS_Pin, GPIO_PIN_RESET);
    
    /* 发送数据并接收返回值 */
    HAL_SPI_TransmitReceive(&hspi2, bufftx, buffrx, size, HAL_MAX_DELAY);
    
    /* 拉高CS引脚，结束传输 */
    HAL_GPIO_WritePin(TMC_CS_GPIO_Port, TMC_CS_Pin, GPIO_PIN_SET);
}

/**
  * @brief  TMC5130写寄存器
  * @param  address: 寄存器地址
  * @param  value: 要写入的值
  * @retval None
  */
void TMC5130_WriteInt(int8_t address, int32_t value)
{
    uint8_t tbuf[5];
    
    /* 最高位为1表示写模式 */
    tbuf[0] = address | 0x80;
    tbuf[1] = (uint8_t)(value >> 24);
    tbuf[2] = (uint8_t)(value >> 16);
    tbuf[3] = (uint8_t)(value >> 8);
    tbuf[4] = (uint8_t)(value);
    
    TMC5130_SPI_Write(tbuf, 5);
}

/**
  * @brief  TMC5130读寄存器
  * @param  address: 寄存器地址
  * @retval 读取的值
  */
int32_t TMC5130_ReadInt(int8_t address)
{
    uint8_t tbuf[5] = {0};
    uint8_t rbuf[5] = {0};
    int32_t value;
    
    /* 最高位为0表示读模式 */
    tbuf[0] = address & 0x7F;
    
    /* 第一次读取的数据无效 */
    TMC5130_SPI_Read(tbuf, rbuf, 5);
    /* 第二次读取的数据有效 */
    TMC5130_SPI_Read(tbuf, rbuf, 5);
    
    /* 组合返回值 */
    value = ((int32_t)rbuf[1] << 24) |
            ((int32_t)rbuf[2] << 16) |
            ((int32_t)rbuf[3] << 8) |
            ((int32_t)rbuf[4]);
    
    return value;
}

/**
  * @brief  设置电机运行电流和半流参数
  * @param  ihold: [0..31]设置电机静止状态下电流
  * @param  irun: [0..31]设置电机运行电流，建议16-31
  * @param  iholddelay: [0..15]保持电流延迟时间
  * @retval None
  */
void TMC5130_IHOLD_IRUN_Init(uint8_t ihold, uint8_t irun, uint8_t iholddelay)
{
    uint32_t value = 0;
    
    /* 参数限制 */
    if (ihold > irun) {
        ihold = irun;
    }
    if (irun < 1) {
        irun = 1;
    }
    if (irun > 31) {
        irun = 31;
    }
    if (iholddelay > 15) {
        iholddelay = 15;
    }
    
    /* 组合寄存器值 */
    value = ((uint32_t)iholddelay << 16) |
            ((uint32_t)irun << 8) |
            ((uint32_t)ihold);
    
    TMC5130_WriteInt(TMC5130_IHOLD_IRUN, value);
}

/**
  * @brief  配置TMC5130的CHOPCONF寄存器
  * @param  toff: 慢衰减阶段持续时间
  * @param  hstrt: 磁滞起始值
  * @param  hend: 磁滞终止值
  * @param  tbl: 消影时间选择
  * @param  md: 细分设置(1,2,4,8,16,32,64,128,256)
  * @retval None
  */
void TMC5130_CHOPCONF_Init(uint8_t toff, uint8_t hstrt, uint8_t hend, uint8_t tbl, uint16_t md)
{
    uint32_t value = 0;
    uint8_t mres;
    uint8_t diss2vs = 0, diss2g = 0, dedge = 0, intpol = 0;
    uint8_t tpfd = 0, vhighchm = 0, vhighfs = 0, chm = 0;
    uint8_t disfdcc = 0, tfd = 0;
    
    /* 计算MRES值 */
    switch (md) {
        case 256: mres = 0; break;
        case 128: mres = 1; break;
        case 64:  mres = 2; break;
        case 32:  mres = 3; break;
        case 16:  mres = 4; break;
        case 8:   mres = 5; break;
        case 4:   mres = 6; break;
        case 2:   mres = 7; break;
        default:  mres = 8; break; /* 1细分 */
    }
    
    /* 组合寄存器值 */
    value = ((uint32_t)diss2vs << 31) |
            ((uint32_t)diss2g << 30) |
            ((uint32_t)dedge << 29) |
            ((uint32_t)intpol << 28) |
            ((uint32_t)mres << 24) |
            ((uint32_t)tpfd << 20) |
            ((uint32_t)vhighchm << 19) |
            ((uint32_t)vhighfs << 18) |
            ((uint32_t)0 << 17) |      /* 保留，设置为0 */
            ((uint32_t)tbl << 15) |
            ((uint32_t)chm << 14) |
            ((uint32_t)0 << 13) |      /* 保留，设置为0 */
            ((uint32_t)disfdcc << 12) |
            ((uint32_t)tfd << 11) |
            ((uint32_t)hend << 7) |
            ((uint32_t)hstrt << 4) |
            ((uint32_t)toff);
    
    TMC5130_WriteInt(TMC5130_CHOPCONF, value);
}